﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Ta
{
    class Program
    {
        private static readonly Dictionary<int, TcpClient> Dic = new Dictionary<int, TcpClient>();
        private static readonly Dictionary<TcpClient, DateTime> lastTime = new Dictionary<TcpClient, DateTime>();
        private static NetworkStream _kongzhins = null;
        const  string _logPath = "log.log";
        private static readonly StringBuilder _logBuilder = new StringBuilder();

        private static IPAddress _bindIp;
        private static int _tbConnectPort = 9800;
        private static int _userConnectPort = 9801;
        static void Main(string[] args)
        {
            _bindIp= Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault(p => !p.ToString().Contains(":"));
            LogWritting();
            Log("监听IP:"+_bindIp);
            Log("Tb连接端口:"+ _tbConnectPort);
            Log("用户使用端口:"+ _userConnectPort);
            ThreadPool.QueueUserWorkItem(Start1);
            ThreadPool.QueueUserWorkItem(Start2);
            while (true)
            {
                var order = Console.ReadLine();
                switch (order.ToLower())
                {
                    case "test":
                        ThreadPool.QueueUserWorkItem(StartTest);
                        break;
                    default:
                        break;
                }
            }
        }

        /// <summary>
        /// 开启让Tb连接的端口
        /// </summary>
        /// <param name="obj"></param>
        public static void Start1(object obj)
        {
            var tl = new TcpListener(_bindIp, _tbConnectPort);//该端口让另外一台机器连接
            tl.Start();
            while (true)
            {
                var tc = tl.AcceptTcpClient();
                try
                {
                    Jieshou(tc);
                }
                catch
                {
                  
                }
            }
        }

        /// <summary>
        /// 开启使用者连接的端口
        /// </summary>
        /// <param name="obj"></param>
        public static void Start2(object obj)
        {
            var tl = new TcpListener(_bindIp, _userConnectPort); //该端口为入口   
            tl.Start();
            var rnd = new Random();
            while (true)
            {
                try
                {
                    var tc = tl.AcceptTcpClient();
                    var biaoji = rnd.Next(1000000000, 2000000000);
                    Dic.Add(biaoji, tc);
                    var bt = BitConverter.GetBytes(biaoji);
                    _kongzhins.Write(bt, 0, bt.Length);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
                
            }
        }

        public static void Jieshou(TcpClient tc)
        {
            var ns = tc.GetStream();
            var bt = new byte[4];
            var count = ns.Read(bt, 0, bt.Length);
            if (count == 2 && bt[0] == 0x6f && bt[1] == 0x6b)
            {
                Log($"Tb已经连接:{tc.Client.RemoteEndPoint}");
                _kongzhins = ns;
                lastTime[tc] = DateTime.Now;
                (new Thread((remote) =>
                {
                    var beat = new byte[] { 66, 69, 65, 84, 33, 33 };
                    var tcClient = (TcpClient)remote;
                    while (true)
                    {
                        Thread.Sleep(10000);
                        if (lastTime.ContainsKey(tcClient))
                        {
                            var time = lastTime[tcClient];
                            if ((DateTime.Now - time).TotalSeconds<120)
                            {
                                continue;
                            }
                            try
                            {
                                tcClient.GetStream().Write(beat, 0, beat.Length);
                            }
                            catch (Exception)
                            {

                                throw;
                            }

                        }
                    }
                })
                { IsBackground = true }).Start(tc);
            }
            else
            {
                var biaoji = BitConverter.ToInt32(bt, 0);
                Lianjie(biaoji, tc);
            }
        }

        private static void Lianjie(int biaoji, TcpClient tc1)
        {
            if (Dic.ContainsKey(biaoji))
            {
                TcpClient tc2 = null;
                Dic.TryGetValue(biaoji, out tc2);
                Dic.Remove(biaoji);
                tc1.SendTimeout = 300000;
                tc1.ReceiveTimeout = 300000;
                tc2.SendTimeout = 300000;
                tc2.ReceiveTimeout = 300000;
                var obj1 = (object)(new[] { tc1, tc2 });//tc1 远程连过来  tc2 浏览器发出去的
                var obj2 = (object)(new[] { tc2, tc1 });
                ThreadPool.QueueUserWorkItem(Transfer, obj1);
                ThreadPool.QueueUserWorkItem(Transfer, obj2);
               
            }
        }

        private static void Transfer(object obj)
        {
            var tc1 = ((TcpClient[])obj)[0];
            var tc2 = ((TcpClient[])obj)[1];
            while (tc1.Connected&&tc2.Connected)
            {
                var ns1 = tc1.GetStream();
                var ns2 = tc2.GetStream();
                try
                {
                    var bt = new byte[10240];
                    var count = ns1.Read(bt, 0, bt.Length);
                    if (count == 0)
                    {
                        ns1.Dispose();
                        ns2.Dispose();
                        tc1.Close();
                        tc2.Close();
                        break;
                    }
                    else
                    {
                        if (lastTime.ContainsKey(tc1))
                        {
                            lastTime[tc1] = DateTime.Now;
                        }
                        if (lastTime.ContainsKey(tc2))
                        {
                            lastTime[tc2] = DateTime.Now;
                        }
                        ns2.Write(bt, 0, count);
                    }
                }
                catch
                {
                    ns1.Dispose();
                    ns2.Dispose();
                    tc1.Close();
                    tc2.Close();
                    break;
                }
            }
        }

        private static void StartTest(object obj)
        {
            var rnd=new Random();
            while (true)
            {
                var client = new TcpClient();
                client.Connect(_bindIp, _userConnectPort);
                var ns = client.GetStream();
                var bts = new byte[1024]; 
                rnd.NextBytes(bts);
                var len = rnd.Next(1, bts.Length);
                ns.Write(bts.Take(len).ToArray(),0, len);
                var rsc=new byte[1024];
                var l=ns.Read(rsc, 0, rsc.Length);
                Console.WriteLine((bts.Take(len).ToArray().SequenceEqual(rsc.Take(l).ToArray()))+" "+len + "   "+l);
                Console.WriteLine("-----------");
                client.Close();
                Thread.Sleep(100);
            }
        }

        private static void Log(string msg)
        {
            var content = $"{DateTime.Now}\r\n {msg}\r\n-------------------------\r\n";
            Console.WriteLine(content);
            lock (_logBuilder)
            {
                _logBuilder.Append(content);
            }
        }
        private static void LogWritting()
        {
            (new Thread(() =>
            {
                using (var fs = new FileStream(_logPath, FileMode.Append, FileAccess.Write))
                {
                    using (var sw = new StreamWriter(fs) { AutoFlush = true })
                    {
                        while (true)
                        {
                            if (_logBuilder.Length > 0)
                            {
                                lock (_logBuilder)
                                {
                                    if (_logBuilder.Length > 0)
                                    {
                                        sw.Write(_logBuilder.ToString());
                                        _logBuilder.Clear();
                                    }
                                }

                            }
                            Thread.Sleep(500);
                        }
                    }

                }

            })
            { IsBackground = true }).Start();
        }
    }
}
